﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SmartProject.Entity;
using SmartProject.Data;

using NUnit.Framework;

namespace SmartProject.Testing
{
    [TestFixture]
    public class Test06_UserAuthentication
    {
        private string _password = Guid.NewGuid().ToString();
        private const string _username = "dlee";
        private const string _email = "seekdavid@hotmail.com";
        private const string _firstName = "David";
        private const string _lastName = "Lee";
        private string[] _roles = new string[1] { "Administrator" };

        [TestFixtureSetUp()]
        public void Start()
        {
            using (var session = DataProvider.Instance.Session)
            {
                using (var transaction = session.BeginTransaction())
                {
                    BusinessRulePreferences.Username userName = new BusinessRulePreferences.Username();
                    userName.SetSelectedBusinessRule(session, "Simple username");

                    User.NewUser(session, _firstName, _lastName, _username, _email, _password, _roles);
                    transaction.Commit();
                    transaction.Dispose();
                }
                session.Close();
                session.Dispose();
            }
        }

        /// <summary>
        /// Authenticate the user with the same username and password.
        /// </summary>
        [Test]
        public void Test01_AuthenticateUserSuccessful()
        {
            using (var session = DataProvider.Instance.Session)
            {
                User user = User.GetUserByUsername(session, _username);
                Assert.IsNotNull(user);
                Assert.IsNull(user.LastLogin);
                Assert.IsNull(user.LastLogout);
                Assert.IsTrue(User.Login(session, _username, _password));
                user = User.GetUserByUsername(session, _username);
                Assert.IsNotNull(user.LastLogin);
                Assert.IsNull(user.LastLogout);
            }
        }

        [Test]
        public void Test02_Logout()
        {
            using (var session = DataProvider.Instance.Session)
            {
                User user = User.GetUserByUsername(session, _username);
                Assert.IsNull(user.LastLogout);
                Assert.IsNotNull(user.LastLogin);
                User.Logout(session, _username);
                user = User.GetUserByUsername(session, _username);
                Assert.IsNotNull(user.LastLogout);
                Assert.IsNotNull(user.LastLogin);
            }
        }

        [Test]
        public void Test03_AuthenticateUserFailure1Time()
        {
            using (var session = DataProvider.Instance.Session)
            {
                Assert.IsFalse(User.Login(session, _username, Guid.NewGuid().ToString()));
                // Reset login Failure.
                Assert.IsTrue(User.Login(session, _username, _password));
                User.Logout(session, _username);
            }
        }

        [Test]
        public void Test04_AuthenticateUserFailure3Times()
        {
            using (var session = DataProvider.Instance.Session)
            {
                for (int i = 0; i < 3; i++)
                {
                    Assert.IsFalse(User.Login(session, _username, Guid.NewGuid().ToString()));
                }

                Assert.Throws(typeof(Exceptions.ExceededFailedLoginCount),
                (delegate()
                {
                    User.Login(session, _username, _password);
                }));
            }
        }

        /// <summary>
        /// Authenticate the user with the different username and password.
        /// </summary>
        [Test]
        public void Test05_AuthenticateNonExistantUser()
        {
            using (var session = DataProvider.Instance.Session)
            {
                Assert.IsFalse(User.Login(session, "tester123", Guid.NewGuid().ToString()));
            }
        }

        [Test]
        public void Test06_ResetUserAndLogin()
        {
            using (var session = DataProvider.Instance.Session)
            {
                _password = User.ResetLogin(session, _username);
                Assert.IsTrue(User.Login(session, _username, _password));
            }
        }

        [Test]
        public void Test07_ChangePassword()
        {
            using (var session = DataProvider.Instance.Session)
            {
                User user = User.GetUserByUsername(session, _username);
                Assert.IsFalse(user.ChangePassword(session, "invalidpassword", "test"));
                string newPassword = "123456";
                Assert.IsTrue(user.ChangePassword(session, _password, newPassword));
                _password = newPassword;
            }
        }

        [TestFixtureTearDown()]
        public void End()
        {
            using (var session = DataProvider.Instance.Session)
            {
                using (var transaction = session.BeginTransaction())
                {
                    User user = User.GetUserByUsername(session, _username);
                    Assert.IsNotNull(user);
                    user.Delete(session);
                    User.Clean(session);

                    transaction.Commit();
                    transaction.Dispose();
                }
                session.Close();
                session.Dispose();
            }
        }
    }
}
